﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Windows.Forms;

using BizElements.Core;
using BizElements.Generator.Oracle;

namespace BizElements.Generator
{
    public partial class OracleConnCtl : UserControl, IMetaDataSourceUi
    {
        public OracleConnCtl()
        {
            InitializeComponent();
        }        
       
        #region Parse and test metadata source.

        private void uiSourceOracleConnect_Click(object sender, EventArgs e)
        {
            CreateAndTestNewMetaDataSource();
        }

        private void CreateAndTestNewMetaDataSource()
        {
            DisposeCurrentMetaDataSource();
            var connStr = ParseConnectionString();
            if (connStr == null)
                return;

            this.MetaDataSource = DbGeneratorComponentFactory.GetMetadataSource(this.dbms, connStr.Build());
            ((OracleMetadataSource)this.MetaDataSource).OnlyUserObjects = this.uiOnlyUserObjects.Checked;
            bool isTestOk = TestConnection();
            if (isTestOk)
            {
                FireConnected();
                this.uiConnect.Enabled = false;
                this.uiDisconnect.Enabled = true;
            }
            else
            {
                this.MetaDataSource = null;
            }
        }        

        private OraConnStringBuilder ParseConnectionString()
        {
            OraConnStringBuilder builder = new OraConnStringBuilder()
            {
                Server = this.uiServer.Text.Trim(),
                Shema = this.uiShema.Text.Trim(),
                Password = this.uiPassword.Text.Trim()
            };

            string[] errors = builder.Validate();
            if (errors.Length > 0)
            {
                builder = null;
                string errmsg = string.Join(Environment.NewLine, errors);
                MessageBox.Show(errmsg);
            }

            return builder;
        }

        private bool TestConnection()
        {
            try
            {
                this.Cursor = Cursors.AppStarting;
                this.MetaDataSource.OpenConnection();
                this.MetaDataSource.CloseConnection();
                return true;
            }
            catch (Exception ex)
            {
                string errmsg = Messages.OracleConnCtl_CannotConnectToDatabase + Environment.NewLine + ex.ToString();
                MessageBox.Show(errmsg, Messages.Error, MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            finally
            {
                this.Cursor = Cursors.Default;
            }
        }

        private void FireConnected()
        {
            if (this.Connected != null)
                Connected(this, new MetaDataSourceEventArgs(this.MetaDataSource));
        }

        #endregion

        #region Disconnect and dispose metadata source.

        private void uiSourceOracleDisconnect_Click(object sender, EventArgs e)
        {
            DisconnectAndDisposeCurrentMetaDataSource();
        }

        private void DisconnectAndDisposeCurrentMetaDataSource()
        {
            DisposeCurrentMetaDataSource();
            this.uiConnect.Enabled = true;
            this.uiDisconnect.Enabled = false;
            FireDisconnected();
        }

        private void FireDisconnected()
        {
            if (this.Disconnected != null)
                Disconnected(this, null);
        }

        private void DisposeCurrentMetaDataSource()
        {
            if (this.MetaDataSource != null)
            {
                this.MetaDataSource.CloseConnection();
                this.MetaDataSource = null;
            }
        }

        #endregion

        #region IMetaDataSourceUi Members.

        [Browsable(false)]
        public UserControl Control
        {
            get { return this; }
        }

        [Browsable(false)]
        public IMetadataSource MetaDataSource { get; private set; }

        DbmsType dbms = DbmsType.Oracle_10g;

        public DbmsType Dbms
        {
            get { return this.dbms; }
            set
            {
                if (DbGeneratorComponentFactory.IsOracle(value))
                    this.dbms = value;
                else
                    throw new ArgumentException(Messages.OracleConnCtl_OnlyOracleDBMSsAreSupported);
            }            
        }

        public event EventHandler<MetaDataSourceEventArgs> Connected;

        public event EventHandler<MetaDataSourceEventArgs> Disconnected;

        #endregion

        #region Settings.

        public void ReadSettings(BizElementsSettings settings)
        {
            DisconnectAndDisposeCurrentMetaDataSource();
            this.uiServer.Text = settings["OracleConn_Server"];
            this.uiShema.Text = settings["OracleConn_Shema"];
            this.uiPassword.Text = settings["OracleConn_Password"];
            string cfgOnlyUserObjects = settings["OracleConn_OnlyUserObjects"];
            this.uiOnlyUserObjects.Checked = (cfgOnlyUserObjects != "false");
        }

        public void WriteSettings(BizElementsSettings settings)
        {
            settings["OracleConn_Server"] = this.uiServer.Text.Trim();
            settings["OracleConn_Shema"] = this.uiShema.Text.Trim();
            settings["OracleConn_Password"] = this.uiPassword.Text.Trim();
            settings["OracleConn_OnlyUserObjects"] = this.uiOnlyUserObjects.Checked.ToString().ToLowerInvariant();
        }

        #endregion

        sealed class OraConnStringBuilder
        {
            #region Properties.

            public string Server { get; set; }
            public string Shema { get; set; }
            public string Password { get; set; }

            #endregion

            #region Methods.

            public string[] Validate()
            {                
                if (string.IsNullOrEmpty(this.Server) || string.IsNullOrEmpty(this.Shema) || string.IsNullOrEmpty(this.Password))
                    return new string[] { Messages.OracleConnCtl_ServerShemaAndPasswordAreRequired };

                return new string[0];
            }

            public string Build()
            {
                const string OraConnFormat = "Data Source={0};User ID={1};Password={2}";
                string connString = string.Format(OraConnFormat, this.Server, this.Shema, this.Password);
                return connString;
            }

            #endregion
        }
    }
}
